import datetime
import json
from hashlib import md5

from tortoise.expressions import F

from app.core.BaseResponse import UnicornException
from app.core.interest_tags import interest_tags
from app.lib.format_num import format_num
from app.model import mysql
from app.service import response as response_service, user as user_service, folder as folder_service
from app.service.folder import create_collect_folder
from app.service.format_datetime import format_datetime
from app.service.user import format_avatar_url
from app.settings.config import SECRET_KEY, DEFAULT_AVATAR, LIMIT
from app.db.redis import r


async def logout(current_user):
    await mysql.UserInfo.filter(id=current_user.id).update(registration_id=None)
    return


async def get_interest_tags(
        current_user,
):
    """
    获取兴趣标签
    :param current_user:
    :return:
    """
    interest = await interest_tags()
    user_tags = await mysql.UserInfo.filter(id=current_user.id).first()
    try:
        result = json.loads(user_tags.interest_tags)
        for filter_tag in interest:
            for item in filter_tag["items"]:
                if item["id"] in result:
                    item["isSelected"] = True
    except Exception as e:
        return interest
    return interest


async def save_interest_tags(tags, current_user):
    """
    保存兴趣标签
    :param tags:
    :param current_user:
    :return:
    """
    tags_id = []
    for filter_tag in tags:
        for item in filter_tag.items:
            if item.isSelected:
                tags_id.append(item.id)
    await mysql.UserInfo.filter(id=current_user.id).update(interest_tags=json.dumps(tags_id, ensure_ascii=False
                                                                                    ), step=3)
    return


async def enshrine_list(page, current_user):
    """
    收藏列表
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    enshrine_all = await mysql.Collect.filter(user_id=current_user.id).limit(limit).offset(offset)
    response_list = []
    for item in enshrine_all:
        result = {}
        result["id"] = item.media_id
        result["url"] = ""
        info = await response_service.response_media(item.media_id)
        try:
            result["type"] = info["type"]
            result["media"] = info["media"]
            result["desc"] = info["desc"]
            if info["type"] == 5:
                result["url"] = info["url"]
        except Exception as e:
            result["type"] = 0
            result["media"] = response_service.format_media_info()
            result["desc"] = ""
            result["url"] = ""
        response_list.append(result)

    return response_list


async def enshrine(enshrines_id, current_user):
    """
    收藏
    :param enshrines_id: 媒体id
    :param current_user:
    :return:
    """
    if not await mysql.Collect.get_or_none(user_id=current_user.id, media_id=enshrines_id):
        if await mysql.Media.get_or_none(id=enshrines_id):
            await mysql.Collect.create(user_id=current_user.id, media_id=enshrines_id)
            await mysql.UserInfo.filter(id=current_user.id).update(collect_number=F("collect_number") + 1)
            await mysql.Media.filter(id=enshrines_id).update(collect_number=F("collect_number") + 1)
            folder = await mysql.Folder.get_or_none(user_id=current_user.id, folder_types=mysql.Folder.Type.collect)
            if not folder:
                folder = await create_collect_folder(current_user.id)
            await folder_service.copy_media2folder(current_user.id, folder.id, enshrines_id)
            await folder_service.reset_folder_and_parent_covers(folder.id)
    return


async def del_enshrine(enshrines_id, current_user):
    """
    取消收藏
    :param enshrines_id: 媒体id
    :param current_user:
    :return:
    """
    folder = await mysql.Folder.get_or_none(user_id=current_user.id, folder_types=mysql.Folder.Type.collect)
    if folder:
        if await mysql.Collect.filter(user_id=current_user.id, media_id=enshrines_id).delete():
            await mysql.UserInfo.filter(id=current_user.id).update(collect_number=F("collect_number") - 1)
            await mysql.Media.filter(id=enshrines_id).update(collect_number=F("collect_number") - 1)
        await folder_service.remove_folder_media(current_user.id, folder.id, enshrines_id)
        await folder_service.reset_folder_and_parent_covers(folder.id)
    return


async def followers_list(page, current_user):
    """
    获取关注列表
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    follow_list = await mysql.Follow.filter(user_id=current_user.id).limit(limit).offset(offset)
    res_list = []
    for item in follow_list:
        fan = await mysql.User.filter(id=item.follow_user_id).first()
        res = {"id": fan.id,
               "nickname": fan.nickname,
               "avatar": format_avatar_url(fan.avatar),
               "a2b": True,
               "b2a": True if await mysql.Follow.filter(user_id=fan.id,
                                                        follow_user_id=current_user.id).first() else False
               }
        res_list.append(res)
    return res_list


async def followers(follow_user_id, current_user):
    """
    关注
    :param follow_user_id:
    :param current_user:
    :return:
    """

    if not await mysql.Follow.filter(user_id=current_user.id, follow_user_id=follow_user_id).first():
        await mysql.Follow.create(user_id=current_user.id, follow_user_id=follow_user_id)
        await mysql.UserInfo.filter(id=current_user.id).update(follow_number=F("follow_number") + 1)
        await mysql.UserInfo.filter(id=follow_user_id).update(fan_number=F("fan_number") + 1)
    return


async def del_followers(follow_user_id, current_user):
    """
    取消关注
    :param follow_user_id:
    :param current_user:
    :return:
    """
    info = await mysql.Follow.filter(user_id=current_user.id, follow_user_id=follow_user_id).delete()
    if info:
        await mysql.UserInfo.filter(id=current_user.id).update(follow_number=F("follow_number") - 1)
        await mysql.UserInfo.filter(id=follow_user_id).update(fan_number=F("fan_number") - 1)
    return


async def fans(page, current_user):
    """
    粉丝列表
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    fan_list = await mysql.Follow.filter(follow_user_id=current_user.id).limit(limit).offset(offset)
    response_list = []
    for item in fan_list:
        follow_user_info = await mysql.User.filter(id=item.user_id).first()
        res = {
            "id": follow_user_info.id,
            "nickname": follow_user_info.nickname,
            "avatar": format_avatar_url(follow_user_info.avatar),
            "a2b": True if await mysql.Follow.filter(user_id=current_user.id,
                                                     follow_user_id=follow_user_info.id).first() else False,
            "b2a": True
        }
        response_list.append(res)
    return response_list


async def like_list(page, current_user):
    """
    点赞列表
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    likes = await mysql.Like.filter(user_id=current_user.id).limit(limit).offset(offset)
    response_likes = []
    for item in likes:
        result = {}
        result["id"] = item.media_id
        result["url"] = ""
        info = await response_service.response_media(item.media_id)
        try:
            result["type"] = info["type"]
            result["media"] = info["media"]
            result["desc"] = info["desc"]
            if info["type"] == 5:
                result["url"] = info["url"]
        except Exception as e:
            result["type"] = 0
            result["media"] = response_service.format_media_info()
            result["desc"] = ""
            result["url"] = ""
        response_likes.append(result)
    return response_likes


async def likes(like_id, current_user):
    """
    点赞
    :param like_id: 点赞媒体id
    :param current_user:
    :return:
    """
    if not await mysql.Like.filter(user_id=current_user.id, media_id=like_id).first():
        if await mysql.Media.get_or_none(id=like_id):
            await mysql.Like.create(user_id=current_user.id, media_id=like_id)
            await mysql.Media.filter(id=like_id).update(like_number=F("like_number") + 1)
    return


async def del_likes(like_id, current_user):
    """
    取消点赞
    :param like_id: 点赞媒体id
    :param current_user:
    :return:
    """
    info = await mysql.Like.filter(user_id=current_user.id, media_id=like_id).delete()
    if info:
        await mysql.Media.filter(id=like_id).update(like_number=F("like_number") - 1)
    return


async def comment_list(page, current_user):
    """
    评论列表
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    comments = await mysql.Comment.filter(user_id=current_user.id).limit(limit).offset(offset)
    user = await mysql.User.filter(id=current_user.id).first()
    response_list = []
    for item in comments:
        result = {}
        result["id"] = user.id
        result["nickname"] = user.nickname
        result["avatar"] = format_avatar_url(user.avatar)
        result["time"] = format_datetime(item.created_time)
        result["desc"] = item.text
        result["photoId"] = item.object_id
        media_object = await mysql.Media.filter(id=item.id).first()
        try:
            if media_object.object_type == 2:
                kind = (await mysql.Case.filter(id=media_object.object_id).first()).kind
                if kind == 1:
                    result["photoKind"] = 2
                if kind == 2:
                    result["photoKind"] = 3
            result["photoKind"] = media_object.object_type
            if media_object.object_type == 1:
                media_info = await mysql.Photo.filter(id=media_object.object_id).first()
                result["photoCover"] = media_info.key
            if media_object.object_type == 2:
                case_info = await mysql.Case.filter(id=media_object.object_id).first()
                media_info = await mysql.Photo.filter(case_id=case_info.id).first()
                result["photoCover"] = media_info.key
            if media_object.object_type == 4:
                media_info = await mysql.Video.filter(id=media_object.object_id).first()
                result["photoCover"] = media_info.key
        except:
            result["photoId"] = 0
            result["photoKind"] = 0
            result["photoCover"] = ""
        response_list.append(result)
    return response_list


async def comment_like(like_id, current_user):
    """
    评论点赞
    :param like_id:
    :param current_user:
    :return:
    """
    if not await mysql.CommentLike.filter(user_id=current_user.id, comment_id=like_id).first():
        await mysql.CommentLike.create(user_id=current_user.id, comment_id=like_id)
        await mysql.Comment.filter(id=like_id).update(like_number=F("like_number") + 1)
    return


async def comment_del_like(like_id, current_user):
    """
    取消点赞评论
    :param like_id:
    :param current_user:
    :return:
    """
    info = await mysql.CommentLike.filter(user_id=current_user.id, comment_id=like_id).delete()
    if info:
        await mysql.Comment.filter(id=like_id).update(like_number=F("like_number") - 1)
    return


async def del_custom_tags(tag, current_user):
    """
    删除自定义标签
    :param tag: 标签
    :param current_user:
    :return:
    """

    user_tags = await user_service.get_user_custom_tags(current_user.id)
    user_media = await mysql.MediaCustomTag.filter(user_id=current_user.id).all()
    if user_tags:
        for item in user_tags:
            if item in tag:
                user_tags.remove(item)
        await mysql.UserInfo.filter(id=current_user.id).update(custom_tags=json.dumps(user_tags, ensure_ascii=False))
    if user_media:
        for my_media in user_media:
            try:
                custom_tags = json.loads(my_media.tags)
            except Exception as e:
                custom_tags = []
            for media_tag in custom_tags:
                if media_tag in tag:
                    custom_tags.remove(media_tag)
            await mysql.MediaCustomTag.filter(id=my_media.id).update(tags=json.dumps(custom_tags, ensure_ascii=False))

    return


async def message_kind_list(page, current_user):
    """
    消息类型列表
    :param page: 页数
    :param current_user: 当前用户
    :return:
    """
    # 开始位置
    size = LIMIT
    data_start = (int(page) - 1) * int(size)
    # 结束位置
    data_end = int(size) + data_start
    message_object = await mysql.Message.all().order_by("-created_time")
    filter_kind = []
    filter_result = []
    for item in message_object:
        if item.message_kind not in filter_kind:
            filter_kind.append(item.message_kind)
            filter_result.append(item)
    response_list = []
    for item in filter_result[data_start:data_end]:
        result = {}
        result["title"] = item.title
        result["desc"] = item.message
        result["time"] = format_datetime(item.created_time)
        result["unreadNumber"] = await mysql.Message.filter(user_id=current_user.id,
                                                            message_kind=item.message_kind, is_read=False).count()
        result["kind"] = item.message_kind
        response_list.append(result)
    return response_list


async def kind_message_list(kid, page, current_user):
    """
    类型消息列表
    :param kid:
    :param page: 页数
    :param current_user: 当前用户
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    message_object = await mysql.Message.filter(user_id=current_user.id, message_kind=kid).limit(limit).offset(offset)
    await mysql.Message.filter(user_id=current_user.id, message_kind=kid).update(is_read=True)
    response_list = []
    for item in message_object:
        result = {}
        result["id"] = item.id
        result["title"] = item.title
        result["desc"] = item.message
        result["time"] = format_datetime(item.created_time)
        try:
            params = json.loads(item.message_params)
            result["imageUrl"] = params["imageUrl"]
            result["url"] = params["url"]
        except Exception as e:
            result["imageUrl"] = ""
            result["url"] = ""
        response_list.append(result)
    return response_list


async def get_user_info(current_user):
    """
    获取编辑个人资料
    :param current_user:
    :return:
    """
    user_info = await mysql.UserInfo.filter(id=current_user.id).first()
    result = {"id": current_user.id,
              "nickname": current_user.nickname,
              "avatar": format_avatar_url(current_user.avatar),
              "gender": user_info.gender,
              "birthday": user_info.birthday,
              "city": user_info.city,
              "cityName": user_info.city_name,
              "personalProfile": user_info.personal_profile}
    return result


async def update_user_info(user_info, current_user):
    """
    更新编辑个人资料
    :param user_info:
    :param current_user:
    :return:
    """
    try:
        if user_info.avatar == "":
            await mysql.User.filter(id=current_user.id).update(nickname=user_info.nickname)
        else:
            await mysql.User.filter(id=current_user.id).update(nickname=user_info.nickname, avatar=user_info.avatar)
        await mysql.UserInfo.filter(id=current_user.id).update(gender=user_info.gender,
                                                               birthday=datetime.datetime.strptime(user_info.birthday,
                                                                                                   '%Y-%m-%d').date(),
                                                               city=user_info.city,
                                                               city_name=user_info.cityName,
                                                               personal_profile=user_info.personalProfile)
    except Exception as e:
        raise UnicornException(-1, errmsg="该昵称已存在~")
    return


async def user_home(current_user):
    """
    获取个人主页详情
    :param current_user:
    :return:
    """

    user_info = await mysql.UserInfo.filter(id=current_user.id).first()
    unread_number = await mysql.Message.filter(user_id=current_user.id, is_read=False).count()
    result = {"id": current_user.id,
              "nickname": current_user.nickname,
              "avatar": format_avatar_url(current_user.avatar),
              "gender": user_info.gender,
              "followNumber": format_num(user_info.follow_number),
              "fanNumber": format_num(user_info.fan_number),
              "collectNumber": format_num(user_info.collect_number),
              "browseNumber": format_num(user_info.browse_number),
              "unreadNumber": str(unread_number) if unread_number < 100 else "99+"}

    return result


async def history_list(page, current_user):
    """
    浏览记录
    :param page:
    :param current_user:
    :return:
    """
    limit: int = LIMIT
    offset: int = (page - 1) * limit
    response_list = []
    histories = await mysql.BrowseHistory.filter(user_id=current_user.id).limit(limit).offset(offset)
    for item in histories:
        result = {}
        result["id"] = item.media_id
        result["url"] = ""
        info = await response_service.response_media(item.media_id)
        try:
            result["type"] = info["type"]
            result["media"] = info["media"]
            result["desc"] = info["desc"]
            if info["type"] == mysql.Media.Type.panorama:
                result["url"] = info["url"]
        except Exception as e:
            result["type"] = 0
            result["media"] = response_service.format_media_info()
            result["desc"] = ""
            result["url"] = ""
        response_list.append(result)

    return response_list


async def val_old_mobile(user, current_user):
    """
    验证旧手机号
    :param user:
    :param current_user:
    :return:
    """
    try:
        redis_user = r.get(f"{user.mobile}:app:captcha").decode()
        if user.captcha != redis_user:
            raise UnicornException(-1, errmsg="验证码错误")
    except:
        raise UnicornException(-1, errmsg="验证码无效")
    token = str(current_user.id) + SECRET_KEY
    md5_token = md5(token.encode('utf8')).hexdigest()
    result = {"token": md5_token}
    return result


async def val_new_mobile(user, current_user):
    """
    验证新手机号验证码并修改手机号
    :param user:
    :param current_user:
    :return:
    """
    try:
        redis_user = r.get(f"{user.mobile}:app:captcha").decode()
        if user.captcha != redis_user:
            raise UnicornException(-1, errmsg="验证码错误")
    except:
        raise UnicornException(-1, errmsg="验证码无效")
    token = str(current_user.id) + SECRET_KEY
    md5_token = md5(token.encode('utf8')).hexdigest()
    if user.token != md5_token:
        raise UnicornException(-1, errmsg="操作违规~")
    await mysql.User.filter(id=current_user.id).update(mobile=user.mobile)
    return


